import React, { useEffect, useState } from "react";
import s from './style.module.css';
import cn from 'classnames'
import Input from '@knownsec/react-component/dist/Input'
import Loading from '@knownsec/react-component/dist/Loading'
import { Checkbox } from 'antd'
import fetchFer from 'API/fetch';
import EmptyData from "../empty/EmptyData";

function CheckboxTree ({ value, onChange, className }) {
	const [fullData, setFullData] = useState({})
	const [treeData, setTreeData] = useState({})
	const [treeCheckMap, setTreeCheckMap] = useState({}) // 三个值 false: 未选中，indeterminate: 部分选中，true: 全选
	const [activeKey, setActiveKey] = useState('')
	const [loading, setLoading] = useState(false)
	const valueMap = React.useMemo(
		() => {
			if (value.length) {
				if (Object.keys(fullData).length > 0) {
					const dataMap = Object.keys(fullData).reduce((t, k) => {
						const values = Object.values(fullData[k]).flat()
						t[k] = values
						return t
					}, {})
					const map = Object.keys(dataMap).reduce((t, i) => {
						const v = dataMap[i].filter(item => { return value.includes(item) })
						if (v.length > 0) {
							t[i] = v
						}
						return t
					}, {})
					return map
				}
			} else {
				return value
			}
			return {}
		},[value, fullData]);
	const levelMap = {
		5: '严重',
		4: '高危',
		3: '中危',
		2: '低危',
		1: '信息'
	}
	const changeData = (value, key, e, type) => {
		let rData = JSON.parse(JSON.stringify(value[key] || []))
		if (type === 'checkAll') {
			if (treeCheckMap[key] === true) {
				rData = []
			} else {
				rData = e
			}
		} else {
			e.map(item => {
				if (rData.indexOf(item) > -1) {
					rData = rData.filter(i => { return i !== item })
				} else {
					rData.push(item)
				}
			})
		}
		const valueChange = Object.fromEntries(Object.entries(Object.assign({}, valueMap, {[key]: rData})).filter(i => { return i[1].length > 0 }))
		setTreeCheckMap(Object.assign({}, treeCheckMap, {[key]: rData.length === 0 ? false : rData.length === Object.keys(treeData[key]).length ? true : 'indeterminate' }))
		onChange(valueChange)
	}
	const [name, setName] = useState('')
	const [searchName, setSearchName] = useState(null)
	const [levelData, setLevelData] = useState(null)
	const getVulnsList = async () => {
		setLoading(true)
		const res = await fetchFer(`/api/v2/vulndb/kb_vulns`, {
			method: 'GET',
			checkStatus: 501,
		}).catch(err => {
			return err;
		});
		const data = res.data.sort((a, b) => { return b.severity - a.severity}).reduce((t, item) => {
			if (t[item.vuln_type[0]?.zh_cn]) {
				t[item.vuln_type[0]?.zh_cn][item.name.zh_cn] = item.source_id
			} else {
				t[item.vuln_type[0]?.zh_cn] = { [item.name.zh_cn]: item.source_id }
			}
			return t
		}, {});
		const level = res.data.reduce((t, item) => {
			if (t[item.vuln_type[0]?.zh_cn]) {
				t[item.vuln_type[0]?.zh_cn][item.name.zh_cn] = item.severity
			} else {
				t[item.vuln_type[0]?.zh_cn] = { [item.name.zh_cn]: item.severity }
			}
			return t
		}, {});
		setLevelData(level)
		setFullData(data);
		setTreeData(data);
		setActiveKey(Object.keys(data)[0] || '')
		setLoading(false)
	};
	useEffect(() => {
		getVulnsList()
	}, [])
	useEffect(() => {
		if (Object.keys(valueMap).length > 0) {
			const map = Object.keys(valueMap).reduce((t, i) => {
				t[i] = valueMap[i].length === 0 ? false : valueMap[i].length === Object.keys(fullData[i]).length ? true : 'indeterminate'
				return t
			}, {})
			setTreeCheckMap(Object.assign({}, treeCheckMap, map))
		}
	}, [valueMap])
	const searchMethod = () => {
		const data = Object.keys(fullData).reduce((t, k) => {
			const newItem = Object.fromEntries(Object.entries(fullData[k]).filter(i => { return i[0].indexOf(searchName) > -1 || !searchName })) || {}
			if (Object.keys(newItem).length > 0) {
				t[k] = newItem
			}
			return t
		}, {})
		const checkMap = Object.keys(treeCheckMap).reduce((t, k) => {
			if (valueMap[k] && data[k]) {
				t[k] = valueMap[k].length === 0 ? false : valueMap[k].length >= Object.keys(data[k]).length ? true : 'indeterminate'
			} else {
				t[k] = false
			}
			return t
		}, {})
		setTreeCheckMap(checkMap)
		setActiveKey(Object.keys(data)[0] || '')
		setTreeData(data)
	}
	useEffect(() => {
		if (typeof searchName === 'string') searchMethod()
	}, [searchName])
	return <div className={cn(s.checkboxTree, className)}>
		<div className={cn('w100p df aic searchBox')}>
			<span>共选择{` ${Object.values(valueMap).filter(value => { return value.length > 0 }).length} `}个漏洞类型，{` ${Object.values(valueMap).flat().length} `}个漏洞</span>
			<Input search value={name} onChange={({ value }) => setName(value)} onSearch={({ value }) => setSearchName(value)} className="w240" placeholder='请输入漏洞名称' />
		</div>
		<div className={cn('df aifs treeContainer')}>
			<Loading show={loading} label='' />
			<div className="treeType">
				{Object.keys(treeData).length > 0 ? Object.keys(treeData).map(key => {
					return <div onClick={e => {
						if (e.target.className === 'ant-checkbox-input') return false
						setActiveKey(key)
					}} className={cn("df aic", { 'activeItem': activeKey === key })}>
						<Checkbox className="w16" onChange={e => changeData(valueMap, key, Object.values(treeData[key]), 'checkAll')} indeterminate={treeCheckMap[key] === 'indeterminate'} checked={treeCheckMap[key] === true} />
						<div className="ml8 df aic jcsb flex1 minW0">
							<div className="flex1 ell minW0" title={key}>{key}</div>
							<div className="w80 tar">{`${valueMap[key]?.length || 0} / ${Object.keys(treeData[key]).length}`}</div>
						</div>
					</div>
				}) : <EmptyData text="暂无数据" className='empty-box pb16' />}
			</div>
			<div className="treeItems flex1 h100p">
				{Object.keys(treeData).length > 0 ? Object.keys(treeData).map((key, index) => {
					return <div className={cn('dn w100p h100p', {['db']: activeKey === key})}>
						<div className="w100p df aic jcsb treeItemHeader">
							<div className="flex1">
								<Checkbox className="w16" onChange={e => changeData(valueMap, key, Object.values(treeData[key]), 'checkAll')}
								 indeterminate={treeCheckMap[key] === 'indeterminate'} checked={treeCheckMap[key] === true} />
								<span className="ml24">漏洞名称</span>
							</div>
							<div className={cn("w80 tac", {'tal': Object.keys(treeData[key]).length > 9})}>
								漏洞等级
							</div>
						</div>
						<div style={{ overflow: 'auto', height: 'calc(100% - 40px)', paddingRight: '17px', position: 'relative' }}>
							{Object.keys(treeData[key]).map(i => {
								return <div className="w100p df aic jcsb fs12 treeItem">
									<div className="flex1 df aic minW0">
										<Checkbox className="w16" checked={valueMap[key] ? valueMap[key].indexOf(treeData[key][i]) > -1 : false} onChange={(e) => changeData(valueMap, key, [treeData[key][i]])} />
										<div className="ml24 ell flex1 minW0" title={i}>{i}</div>
									</div>
									<div className={cn("w80 level-item border0", `level_${levelData[key][i]}`)}>
										{levelMap[levelData[key][i]] || '未知'}
									</div>
								</div>
							})}
						</div>
					</div>
				}) : <EmptyData text="暂无数据" className='empty-box' />}
			</div>
		</div>
	</div>
}

export default CheckboxTree;
